proc wait_for_dbsize {size} {
    set r2 [redis_client]
    wait_for_condition 50 100 {
        [$r2 dbsize] == $size
    } else {
        fail "Target dbsize not reached"
    }
    $r2 close
}

start_server {tags {"multi"}} {
    test {MULTI / EXEC basics} {
        r del mylist
        r rpush mylist a
        r rpush mylist b
        r rpush mylist c
        r multi
        set v1 [r lrange mylist 0 -1]
        set v2 [r ping]
        set v3 [r exec]
        list $v1 $v2 $v3
    } {QUEUED QUEUED {{a b c} PONG}}

    test {DISCARD} {
        r del mylist
        r rpush mylist a
        r rpush mylist b
        r rpush mylist c
        r multi
        set v1 [r del mylist]
        set v2 [r discard]
        set v3 [r lrange mylist 0 -1]
        list $v1 $v2 $v3
    } {QUEUED OK {a b c}}

    test {Nested MULTI are not allowed} {
        set err {}
        r multi
        catch {[r multi]} err
        r exec
        set _ $err
    } {*ERR MULTI*}

    test {MULTI where commands alter argc/argv} {
        r sadd myset a
        r multi
        r spop myset
        list [r exec] [r exists myset]
    } {a 0}

    test {WATCH inside MULTI is not allowed} {
        set err {}
        r multi
        catch {[r watch x]} err
        r exec
        set _ $err
    } {*ERR WATCH*}

    test {EXEC fails if there are errors while queueing commands #1} {
        r del foo1{t} foo2{t}
        r multi
        r set foo1{t} bar1
        catch {r non-existing-command}
        r set foo2{t} bar2
        catch {r exec} e
        assert_match {EXECABORT*} $e
        list [r exists foo1{t}] [r exists foo2{t}]
    } {0 0}

    # Pika not support parameter maxmemory
    # test {EXEC fails if there are errors while queueing commands #2} {
    #     set rd [redis_deferring_client]
    #     r del foo1{t} foo2{t}
    #     r multi
    #     r set foo1{t} bar1
    #     $rd config set maxmemory 1
    #     assert  {[$rd read] eq {OK}}
    #     catch {r lpush mylist{t} myvalue}
    #     $rd config set maxmemory 0
    #     assert  {[$rd read] eq {OK}}
    #     r set foo2{t} bar2
    #     catch {r exec} e
    #     assert_match {EXECABORT*} $e
    #     $rd close
    #     list [r exists foo1{t}] [r exists foo2{t}]
    # } {0 0} {needs:config-maxmemory}

    test {If EXEC aborts, the client MULTI state is cleared} {
        r del foo1{t} foo2{t}
        r multi
        r set foo1{t} bar1
        catch {r non-existing-command}
        r set foo2{t} bar2
        catch {r exec} e
        assert_match {EXECABORT*} $e
        r ping
    } {PONG}

    test {EXEC works on WATCHed key not modified} {
        r watch x{t} y{t} z{t}
        r watch k{t}
        r multi
        r ping
        r exec
    } {PONG}

    test {EXEC fail on WATCHed key modified (1 key of 1 watched)} {
        r set x 30
        r watch x
        r set x 40
        r multi
        r ping
        r exec
    } {}

    test {EXEC fail on WATCHed key modified (1 key of 5 watched)} {
        r set x{t} 30
        r watch a{t} b{t} x{t} k{t} z{t}
        r set x{t} 40
        r multi
        r ping
        r exec
    } {}

    # Pika does not support the sort command
    # test {EXEC fail on WATCHed key modified by SORT with STORE even if the result is empty} {
    #     r flushdb
    #     r lpush foo bar
    #     r watch foo
    #     r sort emptylist store foo
    #     r multi
    #     r ping
    #     r exec
    # } {}

    # Pika does not support the debug command
    # test {EXEC fail on lazy expired WATCHed key} {
    #     r del key
    #     r debug set-active-expire 0

    #     for {set j 0} {$j < 10} {incr j} {
    #         r set key 1 px 100
    #         r watch key
    #         after 101
    #         r multi
    #         r incr key

    #         set res [r exec]
    #         if {$res eq {}} break
    #     }
    #     if {$::verbose} { puts "EXEC fail on lazy expired WATCHed key attempts: $j" }

    #     r debug set-active-expire 1
    #     set _ $res
    # } {} {needs:debug}

    # Pika does not support the debug command
    # test {WATCH stale keys should not fail EXEC} {
    #     r del x
    #     r debug set-active-expire 0
    #     r set x foo px 1
    #     after 2
    #     r watch x
    #     r multi
    #     r ping
    #     assert_equal {PONG} [r exec]
    #     r debug set-active-expire 1
    # } {OK} {needs:debug}

    # Pika does not support the debug command
    # test {Delete WATCHed stale keys should not fail EXEC} {
    #     r del x
    #     r debug set-active-expire 0
    #     r set x foo px 1
    #     after 2
    #     r watch x
    #     # EXISTS triggers lazy expiry/deletion
    #     assert_equal 0 [r exists x]
    #     r multi
    #     r ping
    #     assert_equal {PONG} [r exec]
    #     r debug set-active-expire 1
    # } {OK} {needs:debug}

    # Pika does not support the debug command
    # test {FLUSHDB while watching stale keys should not fail EXEC} {
    #     r del x
    #     r debug set-active-expire 0
    #     r set x foo px 1
    #     after 2
    #     r watch x
    #     r flushdb
    #     r multi
    #     r ping
    #     assert_equal {PONG} [r exec]
    #     r debug set-active-expire 1
    # } {OK} {needs:debug}

    test {After successful EXEC key is no longer watched} {
        r set x 30
        r watch x
        r multi
        r ping
        r exec
        r set x 40
        r multi
        r ping
        r exec
    } {PONG}

    test {After failed EXEC key is no longer watched} {
        r set x 30
        r watch x
        r set x 40
        r multi
        r ping
        r exec
        r set x 40
        r multi
        r ping
        r exec
    } {PONG}

    test {It is possible to UNWATCH} {
        r set x 30
        r watch x
        r set x 40
        r unwatch
        r multi
        r ping
        r exec
    } {PONG}

    test {UNWATCH when there is nothing watched works as expected} {
        r unwatch
    } {OK}

    test {FLUSHALL is able to touch the watched keys} {
        r set x 30
        r watch x
        r flushall
        r multi
        r ping
        r exec
    } {}

    test {FLUSHALL does not touch non affected keys} {
        r del x
        r watch x
        r flushall
        r multi
        r ping
        r exec
    } {PONG}

    test {FLUSHDB is able to touch the watched keys} {
        r set x 30
        r watch x
        r flushdb
        r multi
        r ping
        r exec
    } {}

    test {FLUSHDB does not touch non affected keys} {
        r del x
        r watch x
        r flushdb
        r multi
        r ping
        r exec
    } {PONG}

    # # Pika does not support the swapdb command
    # test {SWAPDB is able to touch the watched keys that exist} {
    #     r flushall
    #     r select 0
    #     r set x 30
    #     r watch x ;# make sure x (set to 30) doesn't change (SWAPDB will "delete" it)
    #     r swapdb 0 1
    #     r multi
    #     r ping
    #     r exec
    # } {} {singledb:skip}

    # # Pika does not support the swapdb command
    # test {SWAPDB is able to touch the watched keys that do not exist} {
    #     r flushall
    #     r select 1
    #     r set x 30
    #     r select 0
    #     r watch x ;# make sure the key x (currently missing) doesn't change (SWAPDB will create it)
    #     r swapdb 0 1
    #     r multi
    #     r ping
    #     r exec
    # } {} {singledb:skip}

    # # Pika does not support the swapdb command
    # test {SWAPDB does not touch watched stale keys} {
    #     r flushall
    #     r select 1
    #     r debug set-active-expire 0
    #     r set x foo px 1
    #     after 2
    #     r watch x
    #     r swapdb 0 1 ; # expired key replaced with no key => no change
    #     r multi
    #     r ping
    #     assert_equal {PONG} [r exec]
    #     r debug set-active-expire 1
    # } {OK} {singledb:skip needs:debug}

    # # Pika does not support the swapdb command
    # test {SWAPDB does not touch non-existing key replaced with stale key} {
    #     r flushall
    #     r select 0
    #     r debug set-active-expire 0
    #     r set x foo px 1
    #     after 2
    #     r select 1
    #     r watch x
    #     r swapdb 0 1 ; # no key replaced with expired key => no change
    #     r multi
    #     r ping
    #     assert_equal {PONG} [r exec]
    #     r debug set-active-expire 1
    # } {OK} {singledb:skip needs:debug}

    # Pika does not support the swapdb command
    # test {SWAPDB does not touch stale key replaced with another stale key} {
    #     r flushall
    #     r debug set-active-expire 0
    #     r select 1
    #     r set x foo px 1
    #     r select 0
    #     r set x bar px 1
    #     after 2
    #     r select 1
    #     r watch x
    #     r swapdb 0 1 ; # no key replaced with expired key => no change
    #     r multi
    #     r ping
    #     assert_equal {PONG} [r exec]
    #     r debug set-active-expire 1
    # } {OK} {singledb:skip needs:debug}

    test {WATCH is able to remember the DB a key belongs to} {
        r select 0
        r set x 30
        r watch x
        r select 1
        r set x 10
        r select 0
        r multi
        r ping
        set res [r exec]
        r select 2
        set res
    } {PONG}

    test {WATCH will consider touched keys target of EXPIRE} {
        r del x
        r set x foo
        r watch x
        r expire x 10
        r multi
        r ping
        r exec
    } {}

    # wait_for_dbsize command not support
    # test {WATCH will consider touched expired keys} {
    #     r flushall
    #     r del x
    #     r set x foo
    #     r expire x 1
    #     r watch x

    #     # Wait for the keys to expire.
    #     wait_for_dbsize 0

    #     r multi
    #     r ping
    #     r exec
    # } {}

    test {DISCARD should clear the WATCH dirty flag on the client} {
        r watch x
        r set x 10
        r multi
        r discard
        r multi
        r incr x
        r exec
    } {11}

    test {DISCARD should UNWATCH all the keys} {
        r watch x
        r set x 10
        r multi
        r discard
        r set x 10
        r multi
        r incr x
        r exec
    } {11}

    # Pika does not support the sync command
    # test {MULTI / EXEC is not propagated (single write command)} {
    #     set repl [attach_to_replication_stream]
    #     r multi
    #     r set foo bar
    #     r exec
    #     r set foo2 bar
    #     assert_replication_stream $repl {
    #         {select *}
    #         {set foo bar}
    #         {set foo2 bar}
    #     }
    #     close_replication_stream $repl
    # } {} {needs:repl}

    # Pika does not support the sync command
    # test {MULTI / EXEC is propagated correctly (multiple commands)} {
    #     set repl [attach_to_replication_stream]
    #     r multi
    #     r set foo{t} bar
    #     r get foo{t}
    #     r set foo2{t} bar2
    #     r get foo2{t}
    #     r set foo3{t} bar3
    #     r get foo3{t}
    #     r exec

    #     assert_replication_stream $repl {
    #         {multi}
    #         {select *}
    #         {set foo{t} bar}
    #         {set foo2{t} bar2}
    #         {set foo3{t} bar3}
    #         {exec}
    #     }
    #     close_replication_stream $repl
    # } {} {needs:repl}

    # Pika does not support the sync command
    # test {MULTI / EXEC is propagated correctly (multiple commands with SELECT)} {
    #     set repl [attach_to_replication_stream]
    #     r multi
    #     r select 1
    #     r set foo{t} bar
    #     r get foo{t}
    #     r select 2
    #     r set foo2{t} bar2
    #     r get foo2{t}
    #     r select 3
    #     r set foo3{t} bar3
    #     r get foo3{t}
    #     r exec

    #     assert_replication_stream $repl {
    #         {multi}
    #         {select *}
    #         {set foo{t} bar}
    #         {select *}
    #         {set foo2{t} bar2}
    #         {select *}
    #         {set foo3{t} bar3}
    #         {exec}
    #     }
    #     close_replication_stream $repl
    # } {} {needs:repl singledb:skip}

    # Pika does not support the sync command
    # test {MULTI / EXEC is propagated correctly (empty transaction)} {
    #     set repl [attach_to_replication_stream]
    #     r multi
    #     r exec
    #     r set foo bar
    #     assert_replication_stream $repl {
    #         {select *}
    #         {set foo bar}
    #     }
    #     close_replication_stream $repl
    # } {} {needs:repl}

    # Pika does not support the sync command
    # test {MULTI / EXEC is propagated correctly (read-only commands)} {
    #     r set foo value1
    #     set repl [attach_to_replication_stream]
    #     r multi
    #     r get foo
    #     r exec
    #     r set foo value2
    #     assert_replication_stream $repl {
    #         {select *}
    #         {set foo value2}
    #     }
    #     close_replication_stream $repl
    # } {} {needs:repl}

    # Pika does not support the sync command
    # test {MULTI / EXEC is propagated correctly (write command, no effect)} {
    #     r del bar
    #     r del foo
    #     set repl [attach_to_replication_stream]
    #     r multi
    #     r del foo
    #     r exec

    #     # add another command so that when we see it we know multi-exec wasn't
    #     # propagated
    #     r incr foo

    #     assert_replication_stream $repl {
    #         {select *}
    #         {incr foo}
    #     }
    #     close_replication_stream $repl
    # } {} {needs:repl}

    # Pika does not support the sync command
    # test {MULTI / EXEC with REPLICAOF} {
    #     # This test verifies that if we demote a master to replica inside a transaction, the
    #     # entire transaction is not propagated to the already-connected replica
    #     set repl [attach_to_replication_stream]
    #     r set foo bar
    #     r multi
    #     r set foo2 bar
    #     r replicaof localhost 9999
    #     r set foo3 bar
    #     r exec
    #     catch {r set foo4 bar} e
    #     assert_match {READONLY*} $e
    #     assert_replication_stream $repl {
    #         {select *}
    #         {set foo bar}
    #     }
    #     r replicaof no one
    # } {OK} {needs:repl cluster:skip}

    # Pika does not support the "config set maxmemory" command
    # test {DISCARD should not fail during OOM} {
    #     set rd [redis_deferring_client]
    #     $rd config set maxmemory 1
    #     assert  {[$rd read] eq {OK}}
    #     r multi
    #     catch {r set x 1} e
    #     assert_match {OOM*} $e
    #     r discard
    #     $rd config set maxmemory 0
    #     assert  {[$rd read] eq {OK}}
    #     $rd close
    #     r ping
    # } {PONG} {needs:config-maxmemory}

    # Pika does not support the "config set lua-time-limit" command
    # test {MULTI and script timeout} {
    #     # check that if MULTI arrives during timeout, it is either refused, or
    #     # allowed to pass, and we don't end up executing half of the transaction
    #     set rd1 [redis_deferring_client]
    #     set r2 [redis_client]
    #     r config set lua-time-limit 10
    #     r set xx 1
    #     $rd1 eval {while true do end} 0
    #     after 200
    #     catch { $r2 multi; } e
    #     catch { $r2 incr xx; } e
    #     r script kill
    #     after 200 ; # Give some time to Lua to call the hook again...
    #     catch { $r2 incr xx; } e
    #     catch { $r2 exec; } e
    #     assert_match {EXECABORT*previous errors*} $e
    #     set xx [r get xx]
    #     # make sure that either the whole transcation passed or none of it (we actually expect none)
    #     assert { $xx == 1 || $xx == 3}
    #     # check that the connection is no longer in multi state
    #     set pong [$r2 ping asdf]
    #     assert_equal $pong "asdf"
    #     $rd1 close; $r2 close
    # }

    # Pika does not support the "config set lua-time-limit" command
    # test {EXEC and script timeout} {
    #     # check that if EXEC arrives during timeout, we don't end up executing
    #     # half of the transaction, and also that we exit the multi state
    #     set rd1 [redis_deferring_client]
    #     set r2 [redis_client]
    #     r config set lua-time-limit 10
    #     r set xx 1
    #     catch { $r2 multi; } e
    #     catch { $r2 incr xx; } e
    #     $rd1 eval {while true do end} 0
    #     after 200
    #     catch { $r2 incr xx; } e
    #     catch { $r2 exec; } e
    #     assert_match {EXECABORT*BUSY*} $e
    #     r script kill
    #     after 200 ; # Give some time to Lua to call the hook again...
    #     set xx [r get xx]
    #     # make sure that either the whole transcation passed or none of it (we actually expect none)
    #     assert { $xx == 1 || $xx == 3}
    #     # check that the connection is no longer in multi state
    #     set pong [$r2 ping asdf]
    #     assert_equal $pong "asdf"
    #     $rd1 close; $r2 close
    # }

    # Pika does not support the "config set lua-time-limit" command
    # test {MULTI-EXEC body and script timeout} {
    #     # check that we don't run an incomplete transaction due to some commands
    #     # arriving during busy script
    #     set rd1 [redis_deferring_client]
    #     set r2 [redis_client]
    #     r config set lua-time-limit 10
    #     r set xx 1
    #     catch { $r2 multi; } e
    #     catch { $r2 incr xx; } e
    #     $rd1 eval {while true do end} 0
    #     after 200
    #     catch { $r2 incr xx; } e
    #     r script kill
    #     after 200 ; # Give some time to Lua to call the hook again...
    #     catch { $r2 exec; } e
    #     assert_match {EXECABORT*previous errors*} $e
    #     set xx [r get xx]
    #     # make sure that either the whole transcation passed or none of it (we actually expect none)
    #     assert { $xx == 1 || $xx == 3}
    #     # check that the connection is no longer in multi state
    #     set pong [$r2 ping asdf]
    #     assert_equal $pong "asdf"
    #     $rd1 close; $r2 close
    # }

    # Pika does not support the "config set lua-time-limit" command
    # test {just EXEC and script timeout} {
    #     # check that if EXEC arrives during timeout, we don't end up executing
    #     # actual commands during busy script, and also that we exit the multi state
    #     set rd1 [redis_deferring_client]
    #     set r2 [redis_client]
    #     r config set lua-time-limit 10
    #     r set xx 1
    #     catch { $r2 multi; } e
    #     catch { $r2 incr xx; } e
    #     $rd1 eval {while true do end} 0
    #     after 200
    #     catch { $r2 exec; } e
    #     assert_match {EXECABORT*BUSY*} $e
    #     r script kill
    #     after 200 ; # Give some time to Lua to call the hook again...
    #     set xx [r get xx]
    #     # make we didn't execute the transaction
    #     assert { $xx == 1}
    #     # check that the connection is no longer in multi state
    #     set pong [$r2 ping asdf]
    #     assert_equal $pong "asdf"
    #     $rd1 close; $r2 close
    # }

    # Pika does not support the "config set min-replicas-to-write" command
    # test {exec with write commands and state change} {
    #     # check that exec that contains write commands fails if server state changed since they were queued
    #     set r1 [redis_client]
    #     r set xx 1
    #     r multi
    #     r incr xx
    #     $r1 config set min-replicas-to-write 2
    #     catch {r exec} e
    #     assert_match {*EXECABORT*NOREPLICAS*} $e
    #     set xx [r get xx]
    #     # make sure that the INCR wasn't executed
    #     assert { $xx == 1}
    #     $r1 config set min-replicas-to-write 0
    #     $r1 close
    # } {0} {needs:repl}

    # Pika does not support the "config set replica-serve-stale-data" command
    # test {exec with read commands and stale replica state change} {
    #     # check that exec that contains read commands fails if server state changed since they were queued
    #     r config set replica-serve-stale-data no
    #     set r1 [redis_client]
    #     r set xx 1

    #     # check that GET and PING are disallowed on stale replica, even if the replica becomes stale only after queuing.
    #     r multi
    #     r get xx
    #     $r1 replicaof localhsot 0
    #     catch {r exec} e
    #     assert_match {*EXECABORT*MASTERDOWN*} $e

    #     # reset
    #     $r1 replicaof no one

    #     r multi
    #     r ping
    #     $r1 replicaof localhsot 0
    #     catch {r exec} e
    #     assert_match {*EXECABORT*MASTERDOWN*} $e

    #     # check that when replica is not stale, GET is allowed
    #     # while we're at it, let's check that multi is allowed on stale replica too
    #     r multi
    #     $r1 replicaof no one
    #     r get xx
    #     set xx [r exec]
    #     # make sure that the INCR was executed
    #     assert { $xx == 1 }
    #     $r1 close
    # } {0} {needs:repl cluster:skip}

    # Pika does not support the "config set maxmemory" command
    # test {EXEC with only read commands should not be rejected when OOM} {
    #     set r2 [redis_client]

    #     r set x value
    #     r multi
    #     r get x
    #     r ping

    #     # enforcing OOM
    #     $r2 config set maxmemory 1

    #     # finish the multi transaction with exec
    #     assert { [r exec] == {value PONG} }

    #     # releasing OOM
    #     $r2 config set maxmemory 0
    #     $r2 close
    # } {0} {needs:config-maxmemory}

    # Pika does not support the "config set maxmemory" command
    # test {EXEC with at least one use-memory command should fail} {
    #     set r2 [redis_client]

    #     r multi
    #     r set x 1
    #     r get x

    #     # enforcing OOM
    #     $r2 config set maxmemory 1

    #     # finish the multi transaction with exec
    #     catch {r exec} e
    #     assert_match {EXECABORT*OOM*} $e

    #     # releasing OOM
    #     $r2 config set maxmemory 0
    #     $r2 close
    # } {0} {needs:config-maxmemory}

    # Pika does not support the xgroup command
    # test {Blocking commands ignores the timeout} {
    #     r xgroup create s{t} g $ MKSTREAM

    #     set m [r multi]
    #     r blpop empty_list{t} 0
    #     r brpop empty_list{t} 0
    #     r brpoplpush empty_list1{t} empty_list2{t} 0
    #     r blmove empty_list1{t} empty_list2{t} LEFT LEFT 0
    #     r bzpopmin empty_zset{t} 0
    #     r bzpopmax empty_zset{t} 0
    #     r xread BLOCK 0 STREAMS s{t} $
    #     r xreadgroup group g c BLOCK 0 STREAMS s{t} >
    #     set res [r exec]

    #     list $m $res
    # } {OK {{} {} {} {} {} {} {} {}}}

    # Pika does not support the SYNC command
    # test {MULTI propagation of PUBLISH} {
    #     set repl [attach_to_replication_stream]

    #     r multi
    #     r publish bla bla
    #     r exec

    #     assert_replication_stream $repl {
    #         {select *}
    #         {publish bla bla}
    #     }
    #     close_replication_stream $repl
    # } {} {needs:repl cluster:skip}

    # Pika does not support the SYNC command
    # test {MULTI propagation of SCRIPT LOAD} {
    #     set repl [attach_to_replication_stream]

    #     # make sure that SCRIPT LOAD inside MULTI isn't propagated
    #     r multi
    #     r script load {redis.call('set', KEYS[1], 'foo')}
    #     r set foo bar
    #     set res [r exec]
    #     set sha [lindex $res 0]

    #     assert_replication_stream $repl {
    #         {select *}
    #         {set foo bar}
    #     }
    #     close_replication_stream $repl
    # } {} {needs:repl}

    # Pika does not support the SYNC command
    # test {MULTI propagation of EVAL} {
    #     set repl [attach_to_replication_stream]

    #     # make sure that EVAL inside MULTI is propagated in a transaction in effects
    #     r multi
    #     r eval {redis.call('set', KEYS[1], 'bar')} 1 bar
    #     r exec

    #     assert_replication_stream $repl {
    #         {select *}
    #         {set bar bar}
    #     }
    #     close_replication_stream $repl
    # } {} {needs:repl}

    # Pika does not support the SYNC command
    # test {MULTI propagation of SCRIPT FLUSH} {
    #     set repl [attach_to_replication_stream]

    #     # make sure that SCRIPT FLUSH isn't propagated
    #     r multi
    #     r script flush
    #     r set foo bar
    #     r exec

    #     assert_replication_stream $repl {
    #         {select *}
    #         {set foo bar}
    #     }
    #     close_replication_stream $repl
    # } {} {needs:repl}

    # Pika does not support the SYNC command
    # tags {"stream"} {
    #     test {MULTI propagation of XREADGROUP} {
    #         set repl [attach_to_replication_stream]

    #         r XADD mystream * foo bar
    #         r XADD mystream * foo2 bar2
    #         r XADD mystream * foo3 bar3
    #         r XGROUP CREATE mystream mygroup 0

    #         # make sure the XCALIM (propagated by XREADGROUP) is indeed inside MULTI/EXEC
    #         r multi
    #         r XREADGROUP GROUP mygroup consumer1 COUNT 2 STREAMS mystream ">"
    #         r XREADGROUP GROUP mygroup consumer1 STREAMS mystream ">"
    #         r exec

    #         assert_replication_stream $repl {
    #             {select *}
    #             {xadd *}
    #             {xadd *}
    #             {xadd *}
    #             {xgroup CREATE *}
    #             {multi}
    #             {xclaim *}
    #             {xclaim *}
    #             {xgroup SETID * ENTRIESREAD *}
    #             {xclaim *}
    #             {xgroup SETID * ENTRIESREAD *}
    #             {exec}
    #         }
    #         close_replication_stream $repl
    #     } {} {needs:repl}
    # }

    # Pika does not support the SAVE command
    foreach {cmd} {SAVE SHUTDOWN} {
        # The return value of Pika is inconsistent with Redis
        # test "MULTI with $cmd" {
        #     r del foo
        #     r multi
        #     r set foo bar
        #     catch {r $cmd} e1
        #     catch {r exec} e2
        #     assert_match {*Command not allowed inside a transaction*} $e1
        #     assert_match {EXECABORT*} $e2
        #     r get foo
        # } {}
    }

    # Pika does not support the BGREWRITEAOF command
    # test "MULTI with BGREWRITEAOF" {
    #     set forks [s total_forks]
    #     r multi
    #     r set foo bar
    #     r BGREWRITEAOF
    #     set res [r exec]
    #     assert_match "*rewriting scheduled*" [lindex $res 1]
    #     wait_for_condition 50 100 {
    #         [s total_forks] > $forks
    #     } else {
    #         fail "aofrw didn't start"
    #     }
    #     waitForBgrewriteaof r
    # } {} {external:skip}

    # Pika does not support the "config set appendonly" command
    # test "MULTI with config set appendonly" {
    #     set lines [count_log_lines 0]
    #     set forks [s total_forks]
    #     r multi
    #     r set foo bar
    #     r config set appendonly yes
    #     r exec
    #     verify_log_message 0 "*AOF background was scheduled*" $lines
    #     wait_for_condition 50 100 {
    #         [s total_forks] > $forks
    #     } else {
    #         fail "aofrw didn't start"
    #     }
    #     waitForBgrewriteaof r
    # } {} {external:skip}

    # Pika does not support the "config set maxmemory" command
    # test "MULTI with config error" {
    #     r multi
    #     r set foo bar
    #     r config set maxmemory bla

    #     # letting the redis parser read it, it'll throw an exception instead of
    #     # reply with an array that contains an error, so we switch to reading
    #     # raw RESP instead
    #     r readraw 1

    #     set res [r exec]
    #     assert_equal $res "*2"
    #     set res [r read]
    #     assert_equal $res "+OK"
    #     set res [r read]
    #     r readraw 0
    #     set _ $res
    # } {*CONFIG SET failed*}
    
     test "Flushall while watching several keys by one client" {
         r flushall
         r mset a{t} a b{t} b
         r watch b{t} a{t}
         r flushall
         r ping
      }
}

# Pika does not support AOF
# start_server {overrides {appendonly {yes} appendfilename {appendonly.aof} appendfsync always} tags {external:skip}} {
#      test {MULTI with FLUSHALL and AOF} {
#          set aof [get_last_incr_aof_path r]
#          r multi
#          r set foo bar
#          r flushall
#          r exec
#          assert_aof_content $aof {
#              {multi}
#              {select *}
#              {set *}
#              {flushall}
#              {exec}
#          }
#          r get foo
#      } {}
# }
